<!doctype html>
<html>

<head>
    <meta charset="utf-8" />
    <title>整体风险情况</title>
    <!-- Antd reset and core css -->
    <link rel="stylesheet" href="{{ url_for('static', filename='vendor/css/reset.css') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='vendor/css/antd.min.css') }}">
    <style>
        .page-wrap { max-width: 1200px; min-width: 600px;margin: 24px auto; padding: 0 16px; }
        .page-title { font-size: 20px; font-weight: 600; margin-bottom: 16px; text-align: center; }

        /* 折叠面板头部 */
        .panel-header { display: flex; flex-direction: column; gap: 4px; margin-bottom: 4px; }
        .legend-row { display: flex; align-items: center; gap: 12px; justify-content: center; }
        .legend { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: #555; }
        .legend-square { width: 12px; height: 12px; display: inline-block; border-radius: 2px; }
        .legend-ng { background: red; }
        .legend-ok { background: green; }
        .legend-miss { background: grey; }

        .panel-title-row { display: flex; align-items: center; gap: 10px; }
        .collapse-btn { cursor: pointer; user-select: none; font-size: 14px; }
        .chart-icon { font-size: 14px; }
        .panel-title { font-size: 16px; font-weight: 600; }

        /* ColorBar 区域 */
        .colorbar-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; }
        .colorbar-card { padding: 12px; background: #fff; }
        .colorbar-title { font-weight: 600; margin-bottom: 8px; font-size: 14px; }
        .colorbar-bar { display: flex; align-items: center; gap: 10px; }
        .bar-track { flex: 0.7; height: 24px; background: #f5f5f5; border-radius: 0; overflow: hidden; display: flex; max-width: 600px; min-width: 200px; }
        .bar-ng { background: red; height: 100%; display: flex; align-items: center; justify-content: center; }
        .bar-ok { background: green; height: 100%; display: flex; align-items: center; justify-content: center; }
        .bar-miss { background: #d9d9d9; height: 100%; display: flex; align-items: center; justify-content: center; }
        /* 取消数值说明，比例由色条体现 */

        /* Tabs 与筛选 */
        .tabs { display: flex; margin-bottom: 12px; justify-content: center; }
        .tab-btn { padding: 6px 12px; border: 1px solid #91caff; color: #1677ff; background: #e6f4ff; cursor: pointer; }
        .tab-btn:first-child { border-radius: 6px 0 0 6px; }
        .tab-btn:last-child { border-radius: 0 6px 6px 0; }
        .tab-btn:not(:first-child) { border-left: none; }
        .tab-btn.active { background: #1677ff; color: #fff; border-color: #1677ff; }

        .filters { display: flex; align-items: center; gap: 16px; margin-bottom: 12px; }
        .filter-group { display: flex; align-items: center; gap: 10px; }
        .filter-sep { width: 150px; height: 16px; }
        .spacer { flex: 1; }
        .search-input { height: 30px; padding: 0 10px; border: 1px solid #d9d9d9; border-radius: 6px; width: 100px; }

        /* 项目ID 标签 */
        .project-label { font-size: 14px; font-weight: 600; margin-bottom: 12px; }
        /* 项目条：左侧项目ID，居中显示工段与状态（含 legend-square） */
        .project-bar { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; margin-bottom: 12px; }
        .project-left { justify-self: start; font-size: 14px; font-weight: 600; }
        .project-center { justify-self: center; display: flex; align-items: center; gap: 12px; color: #555; }

        /* 表格样式 */
        .data-table { width: 100%; border-collapse: collapse; margin-bottom: 16px; }
        .data-table th, .data-table td { border: 1px solid #d9d9d9; padding: 8px 12px; text-align: left; }
        .data-table th { background: #f5f5f5; font-weight: 600; }

        /* 右下角按钮组 */
        .bottom-buttons { display: flex; justify-content: flex-end; gap: 8px; margin-top: 16px; }
        .btn-primary { padding: 6px 16px; background: #1677ff; color: #fff; border: 1px solid #1677ff; border-radius: 6px; cursor: pointer; }
        .btn-primary:hover { background: #4096ff; }

        /* Modal 样式 */
        .modal-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.5); display: flex; align-items: center; justify-content: center; z-index: 1000; }
        .modal-content { background: #fff; border-radius: 8px; padding: 24px; max-width: 500px; width: 90%; max-height: 80vh; overflow-y: auto; }
        .modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
        .modal-title { font-size: 18px; font-weight: 600; }
        .modal-close { background: none; border: none; font-size: 20px; cursor: pointer; color: #666; }
        .modal-close:hover { color: #333; }
        .modal-row { display: flex; margin-bottom: 16px; padding-bottom: 12px; border-bottom: 1px solid #eee; }
        .modal-label { font-weight: 600; min-width: 100px; color: #333; }
        .modal-value { flex: 1; color: #666; }
        .detail-link { color: #1677ff; text-decoration: none; cursor: pointer; }
        .detail-link:hover { text-decoration: underline; }
    </style>
</head>

<body>
    <div class="page-wrap">
    <div id="root"></div>
    </div>
    <script src="{{ url_for('static', filename='vendor/js/react.development.js') }}"></script>
    <script src="{{ url_for('static', filename='vendor/js/react-dom.development.js') }}"></script>
    <script src="{{ url_for('static', filename='vendor/js/dayjs.min.js') }}"></script>
    <script src="{{ url_for('static', filename='vendor/js/antd.min.js') }}"></script>
    <script src="{{ url_for('static', filename='vendor/js/xlsx.full.min.js') }}"></script>
    <script src="{{ url_for('static', filename='vendor/js/babel.min.js') }}"></script>
    <!-- 你的应用脚本（如果使用 Babel 转译，type="text/babel"） -->
    <script type="text/babel">
        // 来自后端注入的单一 JSON（两张表）
        const TABLES = {{ tables|tojson }}; // { A: {name, rows}, B: {name, rows} }
        // 在前端进行数据处理：表名、行数据与色条统计
        const TABLE_NAMES = { A: TABLES.A.name, B: TABLES.B.name };
        const TABLE_ROWS = { A: TABLES.A.rows, B: TABLES.B.rows };
        const summarize = (rows) => {
            const summary = {
                test: { ng: 0, ok: 0, miss: 0 },
                pre: { ng: 0, ok: 0, miss: 0 },
                assembly: { ng: 0, ok: 0, miss: 0 },
                winding: { ng: 0, ok: 0, miss: 0 },
            };
            const sectionKey = { "测试段": "test", "前工序": "pre", "装配段": "assembly", "卷绕段": "winding" };
            rows.forEach(r => {
                const key = sectionKey[r["工段"]];
                if (!key) return;
                const st = r["状态"];
                if (st === "NG项") summary[key].ng += 1;
                else if (st === "OK项") summary[key].ok += 1;
                else summary[key].miss += 1;
            });
            return summary;
        };
        const COLOR_BARS = { A: summarize(TABLE_ROWS.A), B: summarize(TABLE_ROWS.B) };

        // 全局常量与工具
        const SECTION_KEY = { "测试段": "test", "前工序": "pre", "装配段": "assembly", "卷绕段": "winding" };
        const SECTION_LABEL = { test: '测试段', pre: '前工序', assembly: '装配段', winding: '卷绕段' };
        const STATUS_LABEL = { ng: 'NG项', ok: 'OK项', miss: '缺失项' };
        const STATUS_MAP = { ng: 'NG项', ok: 'OK项', miss: '缺失项' };
        const statusClass = (st) => st === 'NG项' ? 'legend-ng' : (st === 'OK项' ? 'legend-ok' : 'legend-miss');

        const filterRows = (rows, filterState) => {
            const sectionAllowed = new Set(Object.entries(filterState.sections).filter(([, v]) => v).map(([k]) => k));
            const statusAllowed = new Set(Object.entries(filterState.types).filter(([, v]) => v).map(([k]) => k));
            const keyword = (filterState.keyword || '').trim();
            return (rows || []).filter(r => {
                const secKey = SECTION_KEY[r["工段"]];
                if (!sectionAllowed.has(secKey)) return false;
                const stInv = Object.entries(STATUS_MAP).find(([, v]) => v === r["状态"])?.[0];
                if (!stInv || !statusAllowed.has(stInv)) return false;
                if (!keyword) return true;
                const line = `${r["工段"]}|${r["全局工序名称"]}|${r["可制造名称"]}|${r["状态"]}|${r["其他信息"]}`;
                return line.includes(keyword);
            });
        };

        const exportToXlsx = (rowsBySheet) => {
            const wb = XLSX.utils.book_new();
            const headers = ["工段", "全局工序名称", "可制造名称", "状态", "其他信息"];
            Object.entries(rowsBySheet).forEach(([sheetName, rows]) => {
                const ws = XLSX.utils.json_to_sheet(rows, { header: headers });
                ws['!cols'] = headers.map(() => ({ wch: 16 }));
                XLSX.utils.book_append_sheet(wb, ws, sheetName.substring(0, 31));
            });
            XLSX.writeFile(wb, "风险评估报告.xlsx");
        };
        {% raw %}
        // 小图例组件
        const Legend = () => (
            <div className="legend-row">
                <span className="legend"><i className="legend-square legend-ng"></i>NG项</span>
                <span className="legend"><i className="legend-square legend-ok"></i>OK项</span>
                <span className="legend"><i className="legend-square legend-miss"></i>缺失项</span>
            </div>
        );

        // ColorBar 单卡片
        function ColorBarCard({ title, ng, ok, miss }) {
            const total = Math.max(ng + ok + miss, 1);
            const ngW = (ng / total) * 100;
            const okW = (ok / total) * 100;
            const missW = (miss / total) * 100;
            return (
                <div className="colorbar-card">
                    <div className="colorbar-bar">
                        <div className="colorbar-title" style={{ minWidth: '50px', marginBottom: 0 }}>{title}: </div>
                        <div className="bar-track">
                            <div className="bar-ng" style={{ width: `${ngW}%` }}>
                                {ng > 0 && <span style={{ color: '#000', fontSize: '10px', fontWeight: 'bold' }}>{ng}</span>}
                            </div>
                            <div className="bar-ok" style={{ width: `${okW}%` }}>
                                {ok > 0 && <span style={{ color: '#000', fontSize: '10px', fontWeight: 'bold' }}>{ok}</span>}
                            </div>
                            <div className="bar-miss" style={{ width: `${missW}%` }}>
                                {miss > 0 && <span style={{ color: '#000', fontSize: '10px', fontWeight: 'bold' }}>{miss}</span>}
                            </div>
                        </div>
                    </div>
                </div>
            );
        }

        // 2x2 ColorBar 容器
        function ColorBarGrid({ data }) {
            return (
                <div className="colorbar-grid">
                    <ColorBarCard title="测试段" ng={data.test.ng} ok={data.test.ok} miss={data.test.miss} />
                    <ColorBarCard title="前工序" ng={data.pre.ng} ok={data.pre.ok} miss={data.pre.miss} />
                    <ColorBarCard title="装配段" ng={data.assembly.ng} ok={data.assembly.ok} miss={data.assembly.miss} />
                    <ColorBarCard title="卷绕段" ng={data.winding.ng} ok={data.winding.ok} miss={data.winding.miss} />
                </div>
            );
        }

        // 可折叠 Panel
        function CollapsiblePanel({ title, children, defaultOpen = false, showLegend = false }) {
            const [open, setOpen] = React.useState(defaultOpen);
            return (
                <div style={{ padding: 12, background: '#fff', marginBottom: 12 }}>
                    <div className="panel-header">
                        {showLegend && <Legend />}
                        <div className="panel-title-row">
                            <span className="collapse-btn" onClick={() => setOpen(v => !v)}>{open ? '▼' : '▶'}</span>
                            <span className="chart-icon">📊</span>
                            <span className="panel-title">{title}</span>
                        </div>
                    </div>
                    {open && (
                        <div>
                            {children}
                        </div>
                    )}
                </div>
            );
        }

        function Tabs({ tabs, activeKey, onChange }) {
            return (
                <div className="tabs">
                    {tabs.map(t => (
                        <button key={t.key} className={"tab-btn" + (t.key === activeKey ? " active" : "")} onClick={() => onChange(t.key)}>{t.label}</button>
                    ))}
                </div>
            );
        }

        function Filters({ state, onChange }) {
            const toggle = (group, key) => {
                onChange({ ...state, [group]: { ...state[group], [key]: !state[group][key] } });
            };
            return (
                <div className="filters">
                    <div className="filter-group">
                        <label><input type="checkbox" checked={state.sections.test} onChange={() => toggle('sections', 'test')} /> 测试段</label>
                        <label><input type="checkbox" checked={state.sections.pre} onChange={() => toggle('sections', 'pre')} /> 前工序</label>
                        <label><input type="checkbox" checked={state.sections.assembly} onChange={() => toggle('sections', 'assembly')} /> 装配段</label>
                        <label><input type="checkbox" checked={state.sections.winding} onChange={() => toggle('sections', 'winding')} /> 卷绕段</label>
                    </div>
                    <div className="filter-sep"></div>
                    <div className="filter-group">
                        <label><input type="checkbox" checked={state.types.ng} onChange={() => toggle('types', 'ng')} /> NG项</label>
                        <label><input type="checkbox" checked={state.types.ok} onChange={() => toggle('types', 'ok')} /> OK项</label>
                        <label><input type="checkbox" checked={state.types.miss} onChange={() => toggle('types', 'miss')} /> 缺失项</label>
                    </div>
                    <div className="spacer"></div>
                    <input className="search-input" placeholder="搜索" value={state.keyword} onChange={e => onChange({ ...state, keyword: e.target.value })} />
                </div>
            );
        }

        // Modal 组件
        function DetailModal({ isOpen, onClose, detailData }) {
            if (!isOpen) return null;
            
            return (
                <div className="modal-overlay" onClick={onClose}>
                    <div className="modal-content" onClick={e => e.stopPropagation()}>
                        <div className="modal-header">
                            <div className="modal-title">详细信息</div>
                            <button className="modal-close" onClick={onClose}>×</button>
                        </div>
                        {/* 顶部信息：加粗表名 + 工序（工段），无前缀文案 */}
                        <div className="modal-row">
                            <div className="modal-label" style={{ display: 'none' }}></div>
                            <div className="modal-value" style={{ paddingLeft: 0 }}>
                                <span style={{ fontWeight: 700 }}>{detailData?.tableName || ''}</span>
                                <span style={{ marginLeft: 8 }}>{detailData?.section || ''}</span>
                            </div>
                        </div>
                        <div className="modal-row">
                            <div className="modal-label">特征明细值:</div>
                            <div className="modal-value">{detailData?.feature || '阳极涂布_JR数出极耳类型'}</div>
                        </div>
                        <div className="modal-row">
                            <div className="modal-label">逻辑描述:</div>
                            <div className="modal-value">{detailData?.logic || '阳极涂布工艺中，JR数出极耳类型的选择直接影响电池性能和安全性'}</div>
                        </div>
                        <div className="modal-row">
                            <div className="modal-label">风险提示:</div>
                            <div className="modal-value">{detailData?.risk || '阳极模切，出极耳类型不当可能导致电池内阻增加，影响充放电效率'}</div>
                        </div>
                    </div>
                </div>
            );
        }

        function App() {
            // 使用后端真实数据
            const barA = COLOR_BARS.A;
            const barB = COLOR_BARS.B;

            const [active, setActive] = React.useState('A');
            const [modalOpen, setModalOpen] = React.useState(false);
            const [modalData, setModalData] = React.useState(null);

            // 为每个表维护独立筛选状态
            const makeDefaultFilter = () => ({
                sections: { test: true, pre: true, assembly: true, winding: true },
                types: { ng: true, ok: false, miss: false },
                keyword: '',
            });
            const [filters, setFilters] = React.useState({ A: makeDefaultFilter(), B: makeDefaultFilter() });
            const currentFilter = filters[active];
            const setFilterForActive = (next) => setFilters(prev => ({ ...prev, [active]: next }));

            const tabs = [
                { key: 'A', label: TABLE_NAMES.A },
                { key: 'B', label: TABLE_NAMES.B },
            ];

            // 使用顶部常量/工具

            const currentRows = React.useMemo(() => (TABLE_ROWS[active] || []), [active]);
            const filteredRows = React.useMemo(() => filterRows(currentRows, currentFilter), [currentRows, currentFilter]);

            // 组装“工段/状态”显示文本和中部 legend 区域
            const selectedSections = React.useMemo(() => {
                const selected = Object.entries(currentFilter.sections).filter(([, v]) => v).map(([k]) => k);
                return selected.length === 4 ? '全部' : selected.map(k => SECTION_LABEL[k]).join('、');
            }, [currentFilter.sections]);
            const selectedStatuses = React.useMemo(() => {
                const selected = Object.entries(currentFilter.types).filter(([, v]) => v).map(([k]) => k);
                return selected.map(k => STATUS_LABEL[k]).join('、') || '（未选择状态）';
            }, [currentFilter.types]);
            const centerLegendItems = React.useMemo(() => {
                const items = [];
                if (currentFilter.types.ng) items.push({ cls: 'legend-ng', label: 'NG项' });
                if (currentFilter.types.ok) items.push({ cls: 'legend-ok', label: 'OK项' });
                if (currentFilter.types.miss) items.push({ cls: 'legend-miss', label: '缺失项' });
                return items;
            }, [currentFilter.types]);

            // 使用顶部 exportToXlsx

            // 下载当前报告：两张表分别按各自筛选导出为两个 sheet
            const filterRowsByTable = (key) => filterRows(TABLE_ROWS[key] || [], filters[key]);

            const onDownloadCurrent = () => {
                const rowsA = filterRowsByTable('A');
                const rowsB = filterRowsByTable('B');
                exportToXlsx({ [TABLE_NAMES.A]: rowsA, [TABLE_NAMES.B]: rowsB });
            };

            const onDownloadAll = () => {
                const all = {
                    [TABLE_NAMES.A]: TABLE_ROWS.A,
                    [TABLE_NAMES.B]: TABLE_ROWS.B,
                };
                exportToXlsx(all);
            };

            return (
                <div>
                    {/* section: 整体风险情况 */}
                    <section id="section_risk_overview">
                        <div className="page-title">整体风险情况</div>
                        {/* 图例只显示一次 */}
                        <div style={{ marginBottom: '16px' }}>
                            <Legend />
                        </div>
                        {/* 两个数据表的概览色条 */}
                        <CollapsiblePanel title={TABLE_NAMES.A} showLegend={false}>
                            <ColorBarGrid data={barA} />
                        </CollapsiblePanel>
                        <CollapsiblePanel title={TABLE_NAMES.B} showLegend={false}>
                            <ColorBarGrid data={barB} />
                        </CollapsiblePanel>
                    </section>

                    {/* section: 风险评估报告 */}
                    <section id="section_risk_assessments" style={{ margin: '24px' }}>
                        <div className="page-title">风险评估报告</div>
                        <Tabs tabs={tabs} activeKey={active} onChange={setActive} />
                        <Filters state={currentFilter} onChange={setFilterForActive} />
                        <div className="bottom-buttons">
                            <button className="btn-primary" onClick={onDownloadCurrent}>下载当前报告</button>
                            <button className="btn-primary" onClick={onDownloadAll}>下载完整表格</button>
                        </div>

                        <div style={{ marginTop: '16px' }}>
                            <div className="project-bar">
                                <div className="project-left">项目ID: {TABLE_NAMES[active]}</div>
                                <div className="project-center">
                                    <span>{selectedSections}</span>
                                    <span>|</span>
                                    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
                                        {centerLegendItems.map((it, i) => (
                                            <span key={i} style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                                                <i className={`legend-square ${it.cls}`}></i>
                                                <span>{it.label}</span>
                                            </span>
                                        ))}
                                    </span>
                                </div>
                                <div></div>
                            </div>
                            <table className="data-table">
                                <thead>
                                    <tr>
                                        <th>工段</th>
                                        <th>全局工序名称</th>
                                        <th>可制造名称</th>
                                        <th>状态</th>
                                        <th>其他信息</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {filteredRows.map((row, idx) => (
                                        <tr key={idx}>
                                            <td>{row["工段"]}</td>
                                            <td>{row["全局工序名称"]}</td>
                                            <td>{row["可制造名称"]}</td>
                                            <td>
                                                <span className={`legend-square ${statusClass(row["状态"])}`} style={{ marginRight: 6 }}></span>
                                                {row["状态"]}
                                            </td>
                                            <td>
                                                {row["其他信息"] === '详情' ? (
                                                    <span 
                                                        className="detail-link" 
                                                        onClick={() => {
                                                            setModalData({ 
                                                                tableName: TABLE_NAMES[active],
                                                                section: row["工段"],
                                                                feature: '阳极涂布_JR数出极耳类型',
                                                                logic: '阳极涂布工艺中，JR数出极耳类型的选择直接影响电池性能和安全性',
                                                                risk: '阳极模切，出极耳类型不当可能导致电池内阻增加，影响充放电效率'
                                                            });
                                                            setModalOpen(true);
                                                        }}
                                                    >
                                                        详情
                                                    </span>
                                                ) : (
                                                    row["其他信息"]
                                                )}
                                            </td>
                                        </tr>
                                    ))}
                                </tbody>
                            </table>
                        </div>
                    </section>

                    {/* Modal 组件 */}
                    <DetailModal 
                        isOpen={modalOpen} 
                        onClose={() => setModalOpen(false)} 
                        detailData={modalData} 
                    />
                </div>
            );
        }

        ReactDOM.createRoot(document.getElementById('root')).render(<App />);
        {% endraw  %}
    </script>
</body>

</html>